package com.xzy.mybatis.cipher.support.strategy.parse;

import cn.hutool.core.collection.CollectionUtil;
import com.alibaba.druid.sql.ast.SQLExpr;
import com.alibaba.druid.sql.ast.SQLStatement;
import com.alibaba.druid.sql.ast.statement.SQLInsertStatement;
import com.xzy.mybatis.cipher.support.registry.CryptoMetadataRegistry;
import com.xzy.mybatis.cipher.support.registry.DataCryptoStrategyRegistry;
import com.xzy.mybatis.cipher.support.strategy.crypto.CryptoStrategy;
import lombok.extern.slf4j.Slf4j;

import java.util.ArrayList;
import java.util.List;

/**
 * @author xzy.xiao
 * @since 2025/1/14  16:31
 */
@Slf4j
public class InsertParseStrategy extends ParseStrategy {

    public InsertParseStrategy(CryptoMetadataRegistry cryptoMetadataRegistry, DataCryptoStrategyRegistry dataCryptoStrategyRegistry) {
        super(cryptoMetadataRegistry, dataCryptoStrategyRegistry);
    }

    @Override
    public List<Object> parse(String datasourceName, SQLStatement sqlStatement, List<Object> originalPropertyValueList) {
        SQLInsertStatement sqlInsertStatement = (SQLInsertStatement) sqlStatement;
        String tableName = sqlInsertStatement.getTableName().getSimpleName();
        String tableAliasName = sqlInsertStatement.getTableSource().getAlias();

        if (!cryptoMetadataRegistry.isCryptoTable(datasourceName, tableName)) {
            return originalPropertyValueList;
        }

        List<SQLExpr> insertColumnList = sqlInsertStatement.getColumns();
        if (CollectionUtil.isEmpty(insertColumnList)) {
            return originalPropertyValueList;
        }

        List<Object> encryptedPropertyValueList = new ArrayList<>(originalPropertyValueList.size());
        for (int i = 0; i < insertColumnList.size(); i++) {

            Object originalPropertyValue = originalPropertyValueList.get(i);
            String insertColumnName = insertColumnList.get(i).toString().replace(tableAliasName + ".", "");

            if (!cryptoMetadataRegistry.isCryptoColumn(datasourceName, tableName, insertColumnName)) {
                encryptedPropertyValueList.add(originalPropertyValue);
                continue;
            }

            CryptoStrategy cryptoStrategy = dataCryptoStrategyRegistry.getStrategy(datasourceName, tableName, insertColumnName);
            if (null == cryptoStrategy) {
                encryptedPropertyValueList.add(originalPropertyValue);
                continue;
            }

            String encryptedPropertyValue = cryptoStrategy.encrypt((String) originalPropertyValue);
            encryptedPropertyValueList.add(encryptedPropertyValue);
        }

        log.debug("Parsed insert sql.\n\t==> original property value:{}\n\t==> encrypted property value:{}", originalPropertyValueList, encryptedPropertyValueList);
        return encryptedPropertyValueList;
    }

}
